#-*- coding: utf-8 -*-

import basicRoute, graphoid, drawing, config, routeList
import gtk, gobject
import pickle

class Editor(gobject.GObject):
    
    __gsignals__ = {
        'route-created'     : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (object,)),
        'route-deleted'     : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (object,)),
        'selection-changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (object,))
    }
    
    def __init__(self, graph, drawArea, oracle):    
    
        gobject.GObject.__init__(self)
      
        self.graph = graph       
        self.drawArea = drawArea
        self.activeNode = None
        self.hilightNode = None
        self.hilightEdge = None
        self.lastNode = None
        self.activeRoute = None
        
        self.selection = None
        
        self.oracle = oracle
        
    def refresh(self):

        self.drawArea.queue_draw()

    def widgetToWorld(self, data):
        x, y = data.x, data.y
        mg = config.margin
        x = (x - mg) / (500 - 2.0 * mg)
        y = 1 - (y - mg) / (500 - 2.0 * mg)
        return x, y    
    
    def delRoute(self, route):   
        self.selection = None
        self.graph.delRoute(route)
        self.emit('route-deleted', route)        
        
    def delEdge(self, edge):
        adj = self.graph.getAdjacentRoutes(edge)
        for a in adj:
            self.delRoute(a)
        self.graph.delEdge(edge)    
        
    def delNode(self, node):
        adj = self.graph.getAdjacentEdges(node)
        for a in adj:
            self.delEdge(a)
        self.graph.delNode(node)    
        
    def routeNextVal(self):
        i = 1
        names = map(lambda x: x.ID, self.graph.getRoutes())
        while True:
            candName = 'route' + str(i)
            if candName not in names:
                return 'route' + str(i) 
            i += 1  

    def addRoute(self): 
        route = self.graph.addRoute(self.routeNextVal())
        self.emit('route-created', route)            

    def motion(self, x, y):
        for n in self.graph.getNodes():
            if n.isInNode(x, y):
                self.hilightNode = n
                break
        else:
            self.hilightNode = None
            for e in self.graph.getEdges():
                if e.isInEdge(x, y):
                    self.hilightEdge = e
                    break
            else:
                self.hilightEdge = None
            
        if x < 0: x = 0
        elif x > 1: x = 1
        if y < 0: y = 0
        elif y > 1: y = 1      
        
        self.cx, self.cy = x, y
        if self.activeNode:
            self.activeNode.x = x
            self.activeNode.y = y
        
        #self.refresh()
        
    def expose(self, widget, drawing):          
        
        rEdges = []
        if self.selection.__class__ == graphoid.basicRoute:
            rEdges = self.selection.getEdges()             
        if self.selection.__class__ == routeList.routeList:
            for route in self.selection:
                rEdges += route.getEdges()
        rEdges = list(set(rEdges))
        
        edges = self.graph.getEdges()
        for e in edges:
            sNode = e.startNode
            eNode = e.endNode
            if e == self.selection:
                color = config.edge.selColor  
            else:
                color = config.edge.color
            if e not in rEdges:  
                drawing.drawArrow(sNode.x, sNode.y, eNode.x, eNode.y, 
                                        e.width, color)
        
        ln = self.lastNode
        if ln:
            drawing.drawLine(ln.x, ln.y, self.cx, self.cy, 
                                    graphoid.basicEdge.width, (0.0, 0.0, 0.0, 1.0)) 
        
        nodes = self.graph.getNodes()
        for n in nodes:
            if n == self.selection:
                drawing.drawCircle(n.x, n.y, n.radius + 0.0065, config.node.selColor)
            color = config.node.normalColor            
            if n.isSafeNode:
                color = config.node.safeColor
            drawing.drawCircle(n.x, n.y, n.radius, color)

        if self.selection.__class__ in [graphoid.basicRoute, routeList.routeList]:
            drawing.paint((0, 0, 0, 0.1))            
        
        for e in rEdges:
            sNode = e.startNode
            eNode = e.endNode
            drawing.drawArrow(sNode.x, sNode.y, eNode.x, eNode.y,
                                    e.width, config.route.selColor)
              

            
    
    def setSelection(self, obj):
        self.selection = obj
        self.emit('selection-changed', obj)
        
    def splitEdge(self, edge, mnx, mny):
        sn, en = edge.startNode, edge.endNode
        mn = self.graph.addNode(mnx, mny)
        e1 = self.graph.addEdge(sn, mn)
        e2 = self.graph.addEdge(mn, en)
        for r in self.graph.getRoutes():
            r.replace(edge, [e1, e2])                    
                    
        self.delEdge(edge) #usuwa kaskadowo trasy, potem sie zmieni
        return mn
        
    def addEdge(self, start, end):
        #self.graph.addEdge(start, end)
        sx, sy = start.getXY()
        ex, ey = end.getXY()
        actNode = start
        
        sect = self.graph.findIntersections(sx, sy, ex, ey)
        question = u'Czy podzielić krawędzie?\nLiczba przecięć: %d' % len(sect)
        if sect and self.oracle.ask(u'Podział krawędzi', question):
            for alpha, edge in sect:
                mnx = alpha * ex + (1 - alpha) * sx
                mny = alpha * ey + (1 - alpha) * sy            
                mn = self.splitEdge(edge, mnx, mny)
                self.graph.addEdge(actNode, mn)
                actNode = mn
        self.graph.addEdge(actNode, end)
            
        self.lastNode = end
        
    def release(self, event):
        x, y = self.widgetToWorld(event)
        left = True if event.button == 1 else False
        
        if not left:
            return
        self.activeNode = None
        
    def clickRoute(self, event):
        x, y = self.widgetToWorld(event)    
        edges = self.graph.getEdges()
        for e in edges:
            if e.isInEdge(x, y):
                break
        else:
            self.setSelection(None)
            return
            
        ar = self.selection
        assert ar.__class__ == graphoid.basicRoute
        are = ar.getEdges()
        if e in are:
            while are[-1] != e:
                del are[-1]
            del are[-1]
        else:
            if ar.length() == 0:
                ar.addEdge(e)
            else:
                chain = self.graph.shortestPath(are[-1].endNode, e.startNode)
                if chain != None:
                    for ce in chain:
                        ar.addEdge(ce)
                    ar.addEdge(e)
        #self.refresh()
                    
    def click(self, event):
        if self.selection.__class__ == graphoid.basicRoute:
            self.clickRoute(event)
            return
            
        x, y = self.widgetToWorld(event)
        
        shift = True if event.state & gtk.gdk.SHIFT_MASK else False
        ctr = True if event.state & gtk.gdk.CONTROL_MASK else False
        right = True if event.button == 3 else False
        left = True if event.button == 1 else False
        
                
        n = self.graph.findNode(x, y)
        e = self.graph.findEdge(x, y)
        
        if right and not self.activeNode:
            self.setSelection(None)
            if n is not None:
                if self.lastNode is not None and self.lastNode != n:
                    self.addEdge(self.lastNode, n)
                self.lastNode = n    
            elif e is not None:
                if e.endNode != self.lastNode:
                    mx, my = e.snap(x, y)
                    sn = e.startNode
                    mn = self.splitEdge(e, mx, my)
                    if self.lastNode is not None and self.lastNode != sn:
                        self.addEdge(self.lastNode, mn)
                    self.lastNode = mn
            else:
                if 0 <= x <= 1 and 0 <= y <= 1: 
                    safe = False
                    n = self.graph.addNode(x, y, safe)
                    if self.lastNode != None:
                        self.addEdge(self.lastNode, n)
                    self.lastNode = n
           
        elif left:
            self.setSelection(None)
            self.lastNode = None
            if n != None:
                if shift:
                    self.delNode(n)
                else:              
                    if ctr:
                        n.isSafeNode = not n.isSafeNode 
                    self.setSelection(n)
                    self.activeNode = n
            elif e != None:
                if shift:
                    self.delEdge(e)
                else:
                    self.setSelection(e)
                
        #self.refresh()
        
        
        
            
            
gobject.type_register(Editor)        
